package com.smzd.projforge.engine;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import com.smzd.projforge.domain.DynaClass;
import com.smzd.projforge.domain.Project;
import com.smzd.projforge.domain.Render;
import com.smzd.projforge.domain.Suit;
import com.smzd.utls.FileUtil;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

public class FMRenderEngine {
    public static final String CODEBASE = "D:/ext/";
    private FreeMarkerConfigurer freeMarkerConfigurer;

    public FMRenderEngine() {
    }

    public FreeMarkerConfigurer getFreeMarkerConfigurer() {
        return freeMarkerConfigurer;
    }

    public void setFreeMarkerConfigurer(FreeMarkerConfigurer freeMarkerConfigurer) {
        this.freeMarkerConfigurer = freeMarkerConfigurer;
    }

    // 根据套件
    public void renderProject(Project project) throws IOException, TemplateException {
        // 收集需要集中起来统一存储的数据
        Map<String, StringBuffer> collections = new HashMap<String, StringBuffer>();
        // 项目代码存储的目标路径
        String baseDir = CODEBASE + project.getName();
        File base = new File(baseDir);
        base.mkdirs();

        // 逐个类进行渲染
        for (DynaClass clazz : project.getClasses()) {
            Suit suit = clazz.getSuit();
            if (suit != null) {// 允许某些类设计成为无需渲染类型的
                renderDynaClass(project, clazz, suit, collections, base);
            }
        }
        // 收集统一存储的内容
        if (collections.size() > 0) {
            for (String name : collections.keySet()) {
                renderCollection(name, collections.get(name).toString(), base);
            }
        }
    }

    private void renderCollection(String name, String content, File base) {
        File file = new File(base, "dist");
        file.mkdirs();
        File file1 = new File(file, name);
        FileUtil.saveContent(content, file1);
    }

    private void renderDynaClass(Project project, DynaClass clazz, Suit suit, Map<String, StringBuffer> collections,
            File base) throws IOException, TemplateException {
        List<Render> renders = suit.getRenders();
        Map<String, Object> root = new HashMap<>();
        root.put("project", project);
        root.put("clazz", clazz);
        for (Render render : renders) {
            executeRender(render, root, base, collections);
        }
    }

    private void executeRender(Render render, Map<String, Object> root, File base, Map<String, StringBuffer> collections)
            throws IOException, TemplateException {
        String path = render(render.getPath(), root);
        String name = render(render.getFilename(), root);
        String ftl = render.getTemplate().getPath();
        boolean seperate = render.isSeperate();
        Template template = getTemplate(ftl);
        if (seperate) {
            File file = new File(base, path.replaceAll("\\.", "/"));
            file.mkdirs();
            File ext = new File(file, name);
            Writer out = new OutputStreamWriter(new FileOutputStream(ext));
            template.process(root, out);
            out.flush();
            out.close();
        } else {
            Writer out = new StringWriter();
            template.process(root, out);
            String result = out.toString();
            StringBuffer sb = collections.get(name);
            if (sb == null) {
                sb = new StringBuffer();
                collections.put(name, sb);
            }
            sb.append(result);
        }
    }

    public String render(String template, Map<String, ?> root) throws IOException, TemplateException {
        String content = null;
        Reader reader = new StringReader(template);
        Writer writer = new StringWriter();
        Template t = new Template("temp_" + template.hashCode(), reader, freeMarkerConfigurer.getConfiguration());
        t.process(root, writer);
        content = writer.toString();

        return content;
    }

    public Template getTemplate(String ftl) throws IOException {
        return freeMarkerConfigurer.getConfiguration().getTemplate("projforge/engine/ftls/" + ftl);
    }
}
